package com.wd.util;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @date : 2012-9-24, 15:22:12
 * @author: long
 */
public class ClassUtil {

	public static String[] getPackageAllClassName(String classLocation, String packageName) {
		String[] packagePathSplit = packageName.split("[.]");
		String realClassLocation = classLocation;
		int packageLength = packagePathSplit.length;
		for (int i = 0; i < packageLength; i++) {
			realClassLocation = realClassLocation + File.separator + packagePathSplit[i];
		}
		File packeageDir = new File(realClassLocation);
		if (packeageDir.isDirectory()) {
			String[] allClassName = packeageDir.list();
			return allClassName;
		}
		return null;
	}

	public static Set<Class<?>> getCommandClasses(Package pack) {
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
		String packageName = pack.getName();
		String packageDirName = packageName.replace('.', '/');
		boolean recursive = true;
		try {
			Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

			while (dirs.hasMoreElements()) {
				URL url = (URL) dirs.nextElement();

				String protocol = url.getProtocol();

				if ("file".equals(protocol)) {
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");

					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return classes;
	}

	public static Set<Class<?>> getCommandClasses0(Package pack) {
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
		String packageName = pack.getName();
		String packageDirName = packageName.replace('.', '/');
		boolean recursive = true;
		try {
			Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

			while (dirs.hasMoreElements()) {
				URL url = (URL) dirs.nextElement();

				String protocol = url.getProtocol();

				if ("file".equals(protocol)) {
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");

					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				}
			}
			List<File> commandJars = SystemUtil.getCommandJar();
			for (File file : commandJars) {
				try {
					JarFile jar = new JarFile(file);
					Enumeration<JarEntry> entries = jar.entries();
					while (entries.hasMoreElements()) {
						JarEntry entry = (JarEntry) entries.nextElement();
						String name = entry.getName();

						if (name.charAt(0) == '/') {
							name = name.substring(1);
						}

						// if (name.startsWith(packageDirName)) {
						int idx = name.lastIndexOf('/');

						if (idx != -1) {
							packageName = name.substring(0, idx).replace('/', '.');
						}

						if ((idx == -1) && (!recursive)) {
							continue;
						}
						if ((!name.endsWith(".class")) || (entry.isDirectory())) {
							continue;
						}
						String className = name.substring(packageName.length() + 1, name.length() - 6);
						try {
							classes.add(Class.forName(packageName + '.' + className));
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}
						// }
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return classes;
	}

	public static Set<Class<?>> getClasses(Package pack) {
		Set classes = new LinkedHashSet();

		boolean recursive = true;

		String packageName = pack.getName();
		String packageDirName = packageName.replace('.', '/');
		try {
			Enumeration dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

			while (dirs.hasMoreElements()) {
				URL url = (URL) dirs.nextElement();

				String protocol = url.getProtocol();

				if ("file".equals(protocol)) {
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");

					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else {
					if (!"jar".equals(protocol)) {
						continue;
					}
					try {
						JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();

						Enumeration entries = jar.entries();

						while (entries.hasMoreElements()) {
							JarEntry entry = (JarEntry) entries.nextElement();
							String name = entry.getName();

							if (name.charAt(0) == '/') {
								name = name.substring(1);
							}

							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');

								if (idx != -1) {
									packageName = name.substring(0, idx).replace('/', '.');
								}

								if ((idx == -1) && (!recursive)) {
									continue;
								}
								if ((!name.endsWith(".class")) || (entry.isDirectory())) {
									continue;
								}
								String className = name.substring(packageName.length() + 1, name.length() - 6);
								try {
									classes.add(Class.forName(packageName + '.' + className));
								} catch (ClassNotFoundException e) {
									e.printStackTrace();
								}
							}
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return classes;
	}

	public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, boolean recursive, Set<Class<?>> classes) {
		File dir = new File(packagePath);

		if ((!dir.exists()) || (!dir.isDirectory())) {
			return;
		}

		File[] dirfiles = dir.listFiles(new MyFileFilter(recursive));
		for (File file : dirfiles) {
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
			} else {
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					classes.add(Class.forName(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
